package timing.ukulele.auth.security.type.image;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.util.StringUtils;
import timing.ukulele.auth.security.LoginTypeEnum;
import timing.ukulele.auth.security.SecurityUtils;
import timing.ukulele.auth.support.RedisOperator;

import static timing.ukulele.auth.constant.RedisConstants.IMAGE_CAPTCHA_PREFIX_KEY;

public class ImageCodeAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
    private boolean postOnly = true;
    private final String usernameParameter = "username";
    private final String passwordParameter = "password";
    private final String captchaParameter = "captcha";
    private final String captchaIdParameter = "captchaId";
    private final RedisOperator<String> stringRedisOperator;
    public ImageCodeAuthenticationFilter(RedisOperator<String> stringRedisOperator) {
        super(new AntPathRequestMatcher(LoginTypeEnum.IMAGE_CODE.getPath(), "POST"));
        this.stringRedisOperator = stringRedisOperator;
    }

    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        if (this.postOnly && !request.getMethod().equals("POST")) {
            throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
        } else {
            String captcha = this.obtainCaptcha(request);
            captcha = captcha != null ? captcha : "";
            String captchaId = this.obtainCaptchaId(request);
            captchaId = captchaId != null ? captchaId : "";
            if (!(StringUtils.hasLength(captcha) && StringUtils.hasLength(captchaId))) {
                throw new AuthenticationServiceException("参数错误");
            } else {
                String key = IMAGE_CAPTCHA_PREFIX_KEY + captchaId;
                String cachedCaptcha = stringRedisOperator.get(key);
                if(!StringUtils.hasLength(cachedCaptcha)){
                    throw new AuthenticationServiceException("验证码不存在或已过期");
                }
                if(!cachedCaptcha.equalsIgnoreCase(captcha)){
                    throw new AuthenticationServiceException("验证码错误");
                }
                stringRedisOperator.delete(key);
            }
            String username = this.obtainUsername(request);
            username = username != null ? username.trim() : "";
            String password = this.obtainPassword(request);
            password = password != null ? password : "";
            if (!(StringUtils.hasLength(username) && StringUtils.hasLength(password))) {
                throw new AuthenticationServiceException("参数错误");
            }
            ImageCodeAuthenticationToken authRequest = new ImageCodeAuthenticationToken(username, password);
            this.setDetails(request, authRequest);
            return this.getAuthenticationManager().authenticate(authRequest);
        }
    }


    protected String obtainPassword(HttpServletRequest request) {
        String encryptedPassword = request.getParameter(this.passwordParameter);
        if (StringUtils.hasLength(encryptedPassword)) {
            String password = SecurityUtils.decryptPassword(encryptedPassword);
            return password;
        }
        return null;
    }

    protected String obtainUsername(HttpServletRequest request) {
        String encryptedUsername = request.getParameter(this.usernameParameter);
        if (StringUtils.hasLength(encryptedUsername)) {
            return SecurityUtils.decryptPassword(encryptedUsername);
        }
        return null;
    }

    protected String obtainCaptcha(HttpServletRequest request) {
        String encryptCaptcha = request.getParameter(this.captchaParameter);
        if (StringUtils.hasLength(encryptCaptcha)) {
            return SecurityUtils.decryptPassword(encryptCaptcha);
        }
        return null;
    }

    protected String obtainCaptchaId(HttpServletRequest request) {
        String encryptedCaptchaId = request.getParameter(this.captchaIdParameter);
        if (StringUtils.hasLength(encryptedCaptchaId)) {
            return SecurityUtils.decryptPassword(encryptedCaptchaId);
        }
        return null;
    }

    protected void setDetails(HttpServletRequest request, ImageCodeAuthenticationToken authRequest) {
        authRequest.setDetails(this.authenticationDetailsSource.buildDetails(request));
    }

    public void setPostOnly(boolean postOnly) {
        this.postOnly = postOnly;
    }
}
